#include "generarcodigo.h"

GenerarCodigo::GenerarCodigo(Sentencia *sentencia, Tabla_Simbolos *variables, Tabla_Simbolos *Tipos)
{

    this->pindir.insert (pair<int,int>(2,2));
    this->pindir.insert (pair<int,int>(3,3));
    this->pindir.insert (pair<int,int>(4,4));
    this->pindir.insert (pair<int,int>(5,5));
    this->pindir.insert (pair<int,int>(6,6));
    this->pindir.insert (pair<int,int>(7,7));
    this->pindir.insert (pair<int,int>(8,0));
    this->pindir.insert (pair<int,int>(9,1));
    this->pindir.insert (pair<int,int>(10,2));
    this->pindir.insert (pair<int,int>(11,3));
    this->pindir.insert (pair<int,int>(12,4));
    this->pindir.insert (pair<int,int>(13,5));
    this->pindir.insert (pair<int,int>(14,0));
    this->pindir.insert (pair<int,int>(15,1));
    this->pindir.insert (pair<int,int>(16,2));
    this->pindir.insert (pair<int,int>(17,3));
    this->pindir.insert (pair<int,int>(18,4));
    this->pindir.insert (pair<int,int>(19,5));

    this->pinmode.insert (pair<int,string>(2,"DDRD"));
    this->pinmode.insert (pair<int,string>(3,"DDRD"));
    this->pinmode.insert (pair<int,string>(4,"DDRD"));
    this->pinmode.insert (pair<int,string>(5,"DDRD"));
    this->pinmode.insert (pair<int,string>(6,"DDRD"));
    this->pinmode.insert (pair<int,string>(7,"DDRD"));
    this->pinmode.insert (pair<int,string>(8,"DDRB"));
    this->pinmode.insert (pair<int,string>(9,"DDRB"));
    this->pinmode.insert (pair<int,string>(10,"DDRB"));
    this->pinmode.insert (pair<int,string>(11,"DDRB"));
    this->pinmode.insert (pair<int,string>(12,"DDRB"));
    this->pinmode.insert (pair<int,string>(13,"DDRB"));
    this->pinmode.insert (pair<int,string>(14,"DDRC"));
    this->pinmode.insert (pair<int,string>(15,"DDRC"));
    this->pinmode.insert (pair<int,string>(16,"DDRC"));
    this->pinmode.insert (pair<int,string>(17,"DDRC"));
    this->pinmode.insert (pair<int,string>(18,"DDRC"));
    this->pinmode.insert (pair<int,string>(19,"DDRC"));



    this->sentencia = sentencia;
    this->Tipos = Tipos;
    this->variables = variables;
    this->Codigo += "#include <avr/io.h> \n";
    this->Codigo += "#include <stdio.h>\n";
    this->Codigo += "#include <string.h>\n";
    this->Codigo += "#include <math.h>\n";


    setStruct();
    setVariables(this->variables);
    this->Codigo += "\nint shiftnumber(int lexema, int inic, int fin){\n";
    this->Codigo += "int number = 0; \nint j = 0;\nint i = 0;\n\n";
    this->Codigo += "if(inic >= fin){\n ";
    this->Codigo += "   for(i=inic; i>=fin; i--){\n";
    this->Codigo += "       if(lexema & 1 << i){\n";
    this->Codigo += "           number |= 1 << j; \n            j++;\n         }\n     }\n } else { \n";
    this->Codigo += "   for(i=inic; i<=fin; i++){\n ";
    this->Codigo += "       if(lexema & 1 << i){\n";
    this->Codigo += "           number |= 1 << j; \n            j++;\n         } \n    }\n }\n ";
    this->Codigo += "   return number;\n }\n";
    this->Codigo += "\nint main(void) {\n";
    this->Codigo+= this->PinCodigo;
    if(this->sentencia!=0){

        gv = new GenerarVariable();
        this->Codigo += this->sentencia->generarCodigo(gv,Tipos,variables);
    }
    this->Codigo += "}\n";
}

string GenerarCodigo::getCodigo()
{
    return this->Codigo;
}

void GenerarCodigo::setVariables(Tabla_Simbolos *variables){
    vector<Item_ts*> v_table =variables->getTable();
    for(int i = 0;i<(int)v_table.size();i++){
        Item_ts* v_item=v_table.at(i);
        string id = "_"+v_item->getId()+"_";

        if(v_item->getTipo()->is().compare("ENTERO")==0){
            this->Codigo += Cvalue(v_item->getTipo())+ id + ";\n";
        }else{
            if(v_item->getTipo()->is().compare("BOOLEANO")==0){
                this->Codigo += Cvalue(v_item->getTipo())+ id + ";\n";
            }else{
                if(v_item->getTipo()->is().compare("CARACTER")==0){
                    this->Codigo += Cvalue(v_item->getTipo())+ id + ";\n";
                }else{
                    if(v_item->getTipo()->is().compare("REAL")==0){
                        this->Codigo += Cvalue(v_item->getTipo())+ id + ";\n";
                    }else{
                        if(v_item->getTipo()->is().compare("ARREGLO")==0){
                            Arreglo *arreglo = (Arreglo*)v_item->getTipo();
                            this->Codigo += Cvalue(arreglo->getTipo())+ " "+id;
                            for(int j=0;j<arreglo->getDims().size();j++){
                                QString a;

                                a.setNum(arreglo->getDims().at(j));
                                this->Codigo += "["+a.toStdString() + "]";
                            }
                            this->Codigo+= ";\n";
                        }else{
                            if(v_item->getTipo()->is().compare("CADENA")==0){
                                Cadena *cadena =(Cadena*) v_item->getTipo();
                                QString c;
                                c.setNum(cadena->getSize()+1);

                                this->Codigo += Cvalue(v_item->getTipo())+" "+ id +"["+c.toStdString()+"];\n";
                            }else{
                                if(v_item->getTipo()->is().compare("FUNCION")==0){
                                    Funcion *funcion = (Funcion*)v_item->getTipo();
                                    this->Codigo += Cvalue(funcion->getTiporetorno());
                                    this->Codigo += " "+ id;
                                    this->Codigo += "(";
                                    setParametros(funcion->getParams());
                                    this->Codigo+="){\n";
                                    setVariables(funcion->getTs());
                                    this->Codigo+="}\n";
                                }else{
                                    if(v_item->getTipo()->is().compare("PROCEDIMIENTO")==0){
                                        Procedimiento *procedimiento = (Procedimiento*)v_item->getTipo();
                                        this->Codigo += "void";
                                        this->Codigo += " "+ id;
                                        this->Codigo += "(";
                                        setParametros(procedimiento->getParams());
                                        this->Codigo+="){\n";
                                        setVariables(procedimiento->getTs());
                                        this->Codigo+="}\n";
                                    }else{
                                        if(v_item->getTipo()->is().compare("REGISTRO")==0){
                                           this->Codigo += Cvalue(v_item->getTipo())+ " "+id + ";\n";
                                        }else{
                                            if(v_item->getTipo()->is().compare("PIN")==0){
                                                Pin *pin = (Pin*)v_item->getTipo();
                                                this->it = this->pindir.find(pin->getPin());
                                                this->it2 =this->pinmode.find(pin->getPin());
                                                int mpin = this->it->second;
                                                string mmode = this->it2->second;

                                                QString mpin_;
                                                mpin_.setNum(mpin,10);
                                                string move = " 1 << "+mpin_.toStdString();
                                                if(pin->getModo()==0){
                                                    this->PinCodigo += mmode + " |=" +move+";\n";
                                                }else if(pin->getModo()==1){
                                                    this->PinCodigo += mmode+ " &= ~(" +move+");\n";
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }


    }
}

void GenerarCodigo::setParametros(Tabla_Simbolos *variables)
{
    vector<Item_ts*> v_table =variables->getTable();
    for(int i = 0;i<(int)v_table.size();i++){
        Item_ts* v_item=v_table.at(i);
        string id = "_"+v_item->getId()+"_";

        if(v_item->getTipo()->is().compare("ENTERO")==0){
            this->Codigo += Cvalue(v_item->getTipo())+ id + ",";
        }else{
            if(v_item->getTipo()->is().compare("BOOLEANO")==0){
                this->Codigo += Cvalue(v_item->getTipo())+ id + ",";
            }else{
                if(v_item->getTipo()->is().compare("CARACTER")==0){
                    this->Codigo += Cvalue(v_item->getTipo())+ id + ",";
                }else{
                    if(v_item->getTipo()->is().compare("REAL")==0){
                        this->Codigo += Cvalue(v_item->getTipo())+ id + ",";
                    }else{
                        if(v_item->getTipo()->is().compare("ARREGLO")==0){
                            Arreglo *arreglo = (Arreglo*)v_item->getTipo();
                            this->Codigo += Cvalue(arreglo->getTipo())+ " "+id;
                            for(int j=0;j<arreglo->getDims().size();j++){
                                QString a;

                                a.setNum(arreglo->getDims().at(j));
                                this->Codigo += "["+a.toStdString() + "]";
                            }
                            this->Codigo+= ",";
                        }else{
                            if(v_item->getTipo()->is().compare("CADENA")==0){
                                Cadena *cadena =(Cadena*) v_item->getTipo();
                                QString c;
                                c.setNum(cadena->getSize()+1);

                                this->Codigo += Cvalue(v_item->getTipo())+" "+ id +"["+c.toStdString()+"],";
                            }else{
                                if(v_item->getTipo()->is().compare("REGISTRO")==0){
                                   this->Codigo += Cvalue(v_item->getTipo())+ " "+id + ",";
                                }else{
                                    if(v_item->getTipo()->is().compare("PIN")==0){
                                     this->Codigo += Cvalue(v_item->getTipo())+ " "+id + ",";
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }


    }
    this->Codigo = this->Codigo.substr(0,this->Codigo.length()-1);
}

void GenerarCodigo::setStruct()
{
    vector<Item_ts*> t_table =this->Tipos->getTable();
    for(int i=0;i<t_table.size();i++){
        Item_ts* t_item=t_table.at(i);
        if(t_item->getTipo()->is().compare("REGISTRO")==0){
            Registro *registro = (Registro*)t_item->getTipo();
            this->Codigo+="typedef struct "+registro->getLexema()+"{\n" ;
            setVariables(registro->getTs());
            this->Codigo+="};\n";
        }
    }

}

string GenerarCodigo::Cvalue(Tipo_ts *value){
    if(value->is().compare("ENTERO")==0){
        return "int ";
    }else if(value->is().compare("BOOLEANO")==0 ){
        return "int ";
    }else if(value->is().compare("CARACTER")==0 ){
        return "char ";
    }else if (value->is().compare("REAL")==0){
        return "float ";
    }else if (value->is().compare("REGISTRO")==0 ){
        Registro *registro = (Registro*)value;
        return registro->getLexema();
    }else if(value->is().compare("CADENA")==0 ){
        return "char ";
    }else if (value->is().compare("PIN")==0 ){
        return "pin ";
    }
}
